package com.ruoyi.common.core.interfaces.imple;

import com.ruoyi.common.exception.base.service.ServiceException;
import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.UUID;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ResourceUtils;

import javax.validation.constraints.NotNull;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @Classname DynamicTemplateImpl
 * @Author: sunluquan
 * @Date: 2022/6/30 16:58
 * @Description TODO
 */
public class DynamicTemplateImpl{

    private final static String HEADER_IMPORT_ELEMENT_NAME = "head";

    private final static String MAIN_BODY_CONTENT_ELEMENT_NAME = "template";

    private final static String SCRIPT_IMPORT_ELEMENT_NAME = "script-import";

    private final static String SCRIPT_CONTENT_ELEMENT_NAME = "script";

    private final static String DYNAMIC_TEMPLATE_PATH = "system/common/dynamicTemplate";

    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    public static final String DEFAULT_PREFIX = "classpath:templates/";

    private String prefix ;

    private String suffix ;

    private String htmlFragment;

    private File dynamicTemplateFile;

    private String encoding;

    public DynamicTemplateImpl(@NotNull String htmlFragment) throws IOException {
        this(htmlFragment,DYNAMIC_TEMPLATE_PATH);
    }

    public DynamicTemplateImpl(String htmlFragment, String dynamicTemplatePath) throws IOException {
        this(htmlFragment,dynamicTemplatePath,DEFAULT_PREFIX,ThymeleafProperties.DEFAULT_SUFFIX);
    }

    public DynamicTemplateImpl(String htmlFragment, String dynamicTemplatePath,String prefix, String suffix) throws IOException {
        this.prefix = prefix;
        this.suffix = suffix;
        this.htmlFragment = htmlFragment;
        this.encoding = DEFAULT_ENCODING.name();

        File dynamicTemplateFile = ResourceUtils.getFile(prefix + dynamicTemplatePath + suffix);

//        System.out.println(StringUtils.format("dynamicTemplateFile:{} , {} , {} , {} ,",dynamicTemplateFile,
//                dynamicTemplateFile.exists(),dynamicTemplateFile.isFile() ,dynamicTemplateFile.isDirectory()));
//
//        System.out.println("dynamicTemplateFile.getName():"+dynamicTemplateFile.getName());
//
//        File file = ResourceUtils.getFile(prefix + dynamicTemplatePath + suffix);
//
//        System.out.println(StringUtils.format("dynamicTemplateFile:{} , {} , {} , {} ,",file,
//                file.exists(),file.isFile() ,file.isDirectory()));

        if(!dynamicTemplateFile.exists() || !dynamicTemplateFile.isFile()){
            throw new ServiceException("file path :{} is not found！",prefix+dynamicTemplatePath + suffix);
        }

        this.dynamicTemplateFile = dynamicTemplateFile;
    }

    /**
     * 新增策略枚举
     */
    enum InsertStrategy{
        APPEND,//在当前节点内追加
        AFTER_AND_REMOVE,//在当前节点后追加 并删除该节点
        BEFORE_AND_REMOVE,//在当前节点前追加 并删除该节点

    }

    private Element getElementByTag(Document document , String tagName){

        Elements elementsByTag = document.getElementsByTag(tagName);

        return CollectionUtils.getFirst(elementsByTag);
    }

    private void replaceElement(Document documentOfTemplate,Document documentOfSource,String tagName,InsertStrategy insertStrategy){

        Element elementOfTemplate = getElementByTag(documentOfTemplate, tagName);
        Element elementByTagOfSource = getElementByTag(documentOfSource, tagName);

        if(StringUtils.isNotNull(elementOfTemplate) && StringUtils.isNotNull(elementByTagOfSource)){

            String htmlOfSource = elementByTagOfSource.html();

            switch (insertStrategy){
                case APPEND:
                    elementOfTemplate.append(htmlOfSource);
                break;
                case AFTER_AND_REMOVE:
                    elementOfTemplate.after(htmlOfSource);
                    elementOfTemplate.remove();
                break;
                case BEFORE_AND_REMOVE:
                    elementOfTemplate.before(htmlOfSource);
                    elementOfTemplate.remove();
                break;
            }
        }
    }

    private void replaceElement(Document documentOfTemplate,Document documentOfSource,String tagName){
        replaceElement(documentOfTemplate,documentOfSource,tagName,InsertStrategy.AFTER_AND_REMOVE);
    }

    public File getFillFile(){

        Document documentOfHtmlFragment = Jsoup.parse(htmlFragment);
        Document rootDocument = getRootDocument();

        replaceElement(rootDocument,documentOfHtmlFragment,HEADER_IMPORT_ELEMENT_NAME);

        replaceElement(rootDocument,documentOfHtmlFragment,MAIN_BODY_CONTENT_ELEMENT_NAME);

        replaceElement(rootDocument,documentOfHtmlFragment,SCRIPT_IMPORT_ELEMENT_NAME);

        replaceElement(rootDocument,documentOfHtmlFragment,SCRIPT_CONTENT_ELEMENT_NAME,InsertStrategy.APPEND);

        return documentToFile(rootDocument);
    }

    private File documentToFile(Document rootDocument){

        File tempFile = null;
        try {
            tempFile = File.createTempFile(UUID.randomUUID().toString(), suffix);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException("创建临时文件失败！");
        }

        try (OutputStream outputStream = new FileOutputStream(tempFile);
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);) {
            outputStreamWriter.write(rootDocument.html());
        }catch (IOException e){
            e.printStackTrace();
            throw new ServiceException("写入数据至文件：{} 失败！",tempFile.getName());
        }

        return tempFile;
    }

    /**
     *
     * @return
     */
    private Document getRootDocument(){
        try {
            return Jsoup.parse(this.dynamicTemplateFile);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }


}
